module SRI
  class Parser
    def self.make_ast( tree )
      i = 0
      children = []
      
      while i < tree.size
        case tree[i]
        when :block, :array
          children << make_block( tree[i+1...tree.size] )
          break
        when :defn
          children << make_method( tree[i+1], tree[i+2] )
          i += 3
        when :defs
          children << make_class_method( tree[i+1], tree[i+2], tree[i+3] )
          i += 4
        when :if
          children << make_conditional( tree[i+1], tree[i+2], tree[i+3] )
          i += 4
        when :fcall
          children << make_function_call( tree[i+1], tree[i+2] )
          i += 3
        when :lasgn
          children << make_lasgn( tree[i+1], tree[i+2] )
          i += 3
        when :iasgn
          children << make_iasgn( tree[i+1], tree[i+2] )
          i += 3
        when :lvar
          children << Variable.new( tree[i+1] )
          i += 2
        when :const
          children << Constant.new( tree[i+1] )
          i += 2
        when :lit
          children << Literal.new( tree[1] )
          i += 2
        when :nil, :true, :false
          children << Literal.new( tree[i] )
          i += 1
        when :str
          children << Literal.new( tree[i+1] )
          i += 2
        when :call
          children << make_call( tree[i+1], tree[i+2], tree[i+3] )
          break
        when :class
          children << make_class( tree[i+1], tree[i+2], tree[i+3] )
          i += 4
        when :scope
          children << make_ast( tree[i+1] )
          break
        when :return
          children << Return.new( make_ast( tree[i+1] ) )
          break
        else
          raise StandardError.new("error making AST for #{tree[i].inspect} (item #{i})") if DEBUG
          break
        end
      end
      
      (children.size <= 1) ? children[0] : children
    end

    def self.make_block( exprs )
      Block.new( exprs.map { |expr| make_ast( expr) } )
    end
    
    def self.make_method( name, scope_tree )
      args = scope_tree[1][1][1...scope_tree[1][1].size]
      body = Parser.make_ast( scope_tree[1][2] )
      Method.new( name, args, body )
    end
    
    def self.make_class_method( target, name, scope_tree )
      # unimplemented
      nil
    end
    
    def self.make_conditional( cond, e1, e2 )
      Conditional.new( make_ast(cond), make_ast(e1), make_ast(e2) )
    end
    
    def self.make_function_call( function_name, args_tree )
      FunctionCall.new( function_name, Parser.make_args_list( args_tree[1...args_tree.size] ) )
    end

    def self.make_args_list( args_tree )
      args_tree.map { |arg| Parser.make_ast( arg ) }
    end

    def self.make_lasgn( identifier, expr )
      Assignment.new( identifier, Parser.make_ast( expr ) )
    end
    
    def self.make_iasgn( identifier, expr )
      IVarAssignment.new( identifier, Parser.make_ast( expr ) )
    end
    
    def self.make_call( target, name, args )
      unless args.nil?
        args.slice!(0) if args[0] == :array
        args = args.map {|a| make_ast(a) }
      end
      Call.new( make_ast(target), name, args )
    end
    
    def self.make_class( name, superclass, instance_methods )
      c = Class.new( name, superclass )
      make_ast( instance_methods ).each {|m| c.instance_methods[ m.name ] = m unless m.nil? }
      c
    end
  end
end
